package erfgame.frontend.desktop.view.operation;

import java.awt.Container;
import java.awt.Frame;

import javax.swing.JComponent;
import javax.swing.JDialog;

import erfgame.core.Operation;
import erfgame.core.OperationProgress;
import erfgame.core.OperationProgressEvent;
import erfgame.core.OperationProgressListener;
import erfgame.core.OperationResultListener;
import erfgame.core.world.generator.WorldGeneratorUtils;

import erfgame.frontend.desktop.controller.AbstractController;

public class OperationViewController extends AbstractController {
	
	@SuppressWarnings(value="unchecked")
	private Operation operation;
	
	private OperationProgressListener progressListener;
	private OperationView view;
	
	public static final<K, E extends Throwable> void showOperationDialog( 
			final Operation<K, E> operation, 
			JComponent component,
			final OperationResultListener<K, E> result
	) {
		Container container = component.getTopLevelAncestor();
		Frame frame;
		if( container instanceof Frame ) {
			frame = (Frame)container;
		} else {
			frame = null;
		}
		final JDialog dialog = new JDialog(frame, "Progress", true);
		
		OperationViewController operationController;
		operationController = new OperationViewController();
		
		operationController.setOperation(operation);
		
		OperationView operationView = operationController.getView();
		
		dialog.add( operationView.getComponent() );
		dialog.setDefaultCloseOperation( JDialog.DO_NOTHING_ON_CLOSE );
		dialog.pack();
		dialog.setResizable(false);
		dialog.setLocation(
				frame.getX() + (frame.getWidth() - dialog.getWidth())/2, 
				frame.getY() + (frame.getHeight() - dialog.getHeight())/2
		);
		
		Thread thread = new Thread() {
			@Override
			@SuppressWarnings(value="unchecked")
			public void run() {
				try {
					K k = operation.perform();
					if( result != null ) {
						result.success(k);
					}
				} catch( Throwable ex ) {
					if( result != null ) {
						result.failure((E)ex);
					}
				} finally {
					dialog.setVisible(false);
				}
			}
		};
		thread.start();
		
		dialog.setVisible(true);

	}
	
	public OperationViewController() {
		progressListener = new OperationProgressListener() {
			
			public void progressUpdated(OperationProgressEvent e) {
				setProgress( e.getProgress() );
			}
		};
		view = new OperationView();
		view.init();
	}
	
	public OperationView getView() {
		return this.view;
	}
	
	@SuppressWarnings(value="unchecked")
	public void setOperation( Operation operation ) {
		if( this.operation != null ) {
			this.operation.removeOperationProgressListener( progressListener );
		}
		this.operation = operation;
		operation.addOperationProgressListener( progressListener );
		setProgress( operation.getProgress() );
	}
	
	public void setProgress( OperationProgress progress ) {
		int steps = progress.getStep();
		int maxSteps = progress.getNumberOfSteps()-1;
		this.view.setProgress(steps, maxSteps);
		// TODO internationalisation
		this.view.setMessage( progress.getName() );
		if( steps == maxSteps ) {
			this.fireControllerCompleted();
		}
		
	}
}
